package net.zwj;

/**
 * 修改Class文件中的常量池，替换其中System类为 HackSystem类
 * 
 */
public class ClassModifier {

	/**
	 * Class文件中常量池的起始偏移量
	 */
	private static final int CONSTANT_POOL_COUNT_INDEX = 8;

	/**
	 * CONSTANT_Utf8_info常量tag标志
	 */
	private static final int CONSTANT_Utf8_info = 1;

	/**
	 * 常量池中11中常量的长度，CONSTANT_Utf8_info常量类型除外，因为这种类型是不定长的。
	 */
	private static final int[] CONSTANT_ITEM_LENGTH = { -1, -1, 5, -1, 5, 9, 9,
			3, 3, 5, 5, 5, 5 };
	
	private static final int u1 = 1;
	private static final int u2 = 2;
	
	private byte[] classByte;
	
	
	public ClassModifier(byte[] classByte) {
		this.classByte = classByte;
	}

	/**
	 * 替换常量池中CONSTANT_Utf8_info常量的内容
	 * @param oldStr 修改前的字符串
	 * @param newStr 修改后的字符串
	 * @return
	 */
	public byte[] modifyUTF8Constant(String oldStr, String newStr) {
		int cpc = getConstantPoolCount();
		int offset = CONSTANT_POOL_COUNT_INDEX+u2;
		byte[] bytes = null;
		String str = null;
		for(int i=0;i<cpc;i++){
			int tag = ByteUtils.byte2Int(classByte, offset, u1);
			if(tag==CONSTANT_Utf8_info){//UTF8字符串
				int len = ByteUtils.byte2Int(classByte, offset+u1, u2);
				offset+=u1+u2;
				str = ByteUtils.bytes2String(classByte, offset, len);
				if(oldStr.equalsIgnoreCase(str)){
					byte[] strBytes = ByteUtils.string2Bytes(newStr);
					byte[] strLen = ByteUtils.int2Bytes(newStr.length(), u2);
					bytes = ByteUtils.bytesReplace(classByte, offset-u2, u2, strLen);
					bytes = ByteUtils.bytesReplace(bytes, offset, len, strBytes);
					break;//只简单替换System一个字符串
				}else{
					offset+=len;
				}
			}else{
				offset +=CONSTANT_ITEM_LENGTH[tag];
			}
		}
		return bytes;
	}
	
	/**
	 * 得到常量池中常量的数量
	 * @return
	 */
	public int getConstantPoolCount(){
		return ByteUtils.byte2Int(classByte, CONSTANT_POOL_COUNT_INDEX, u2);
	}

}
